﻿using Sidvall.WorkItemManager.Data.Entity.Entities;
using Sidvall.WorkItemManager.Data.Fields;
using System.Linq;
using System.Threading.Tasks;

namespace Sidvall.WorkItemManager.Data.Entity.Model.StorageManagers
{
    public static partial class WorkItemSensorManager
    {
        static partial void OnExecute(StorageManager storageManager, Sidvall.Business.DataPortalContext<Sidvall.Data.CommandCriteria, Sidvall.Data.CommandCriteria> dataPortalContext)
        {
            dataPortalContext.Tasks.Add(OnExecuteTask(storageManager, dataPortalContext));
        }
        private static async Task OnExecuteTask(StorageManager storageManager, Sidvall.Business.DataPortalContext<Sidvall.Data.CommandCriteria, Sidvall.Data.CommandCriteria> dataPortalContext)
        {
            bool result;

            switch (dataPortalContext.OperationContext.CriteriaId)
            {
                case ParameterManager.WorkItemSensorGetParameterName:
                    var sensors = await GetSensorValuesAsync(storageManager,
                        dataPortalContext.Parameters.ValueToNullableInt64(WorkItemField.WorkItemId.ToString()).Value).ConfigureAwait(false);
                    dataPortalContext.Parameters.Add(ParameterManager.SensorsParameterName, sensors);
                    break;
                case ParameterManager.WorkItemSensorUpdateParameterName:
                    result = await UpdateSensorValuesAsync(storageManager,
                        dataPortalContext.Parameters.ValueToNullableInt64(WorkItemField.WorkItemId.ToString()).Value,
                        dataPortalContext.Parameters.ValueToBoolean("LogOldValue", false),
                        dataPortalContext.Parameters.ValueToObject<SensorValueCollection>(ParameterManager.SensorsParameterName, null)).ConfigureAwait(false);
                    if (result)
                        dataPortalContext.Result = Sidvall.Business.DataPortalResult.Ok;
                    else
                        dataPortalContext.Result = Sidvall.Business.DataPortalResult.Skipped;
                    break;
                default:
                    break;
            }
        }

        #region GetSensorValuesAsync

        public static async Task<SensorValueCollection> GetSensorValuesAsync(StorageManager storageManager, long workItemId)
        {
            System.Linq.IQueryable<WorkItemSensor> query;
            SensorValue sensor;

            var sensors = new SensorValueCollection();
            query = (from o in storageManager.ObjectContext.WorkItemSensor
                     where (o.WorkItemId == workItemId)
                     select o);
            var items = await Sidvall.WorkItemManager.Data.Entity.SystemContext.Current.DataManager.GetEntityObjectsAsync(query).ConfigureAwait(false);
            if (items == null)
                return sensors;
            foreach (var item in items)
            {
                sensor = new SensorValue()
                {
                    Name = item.Name,
                    Value = item.Value,
                    ValueTimestamp = item.ValueTimestamp,
                };
                sensors.Add(sensor);
            }

            return sensors;
        }

        #endregion
        #region UpdateSensorValuesAsync

        public static async Task<bool> UpdateSensorValuesAsync(StorageManager storageManager, long workItemId, bool logOldValue, SensorValueCollection sensorValues)
        {
            System.Linq.IQueryable<WorkItemSensor> query;
            WorkItemSensorLogCollection workItemSensorLogs;
            WorkItemSensorLog workItemSensorLog;
            SensorValue sensorValue;
            string[] names;
            int iMax;

            if (sensorValues == null)
                return false;
            var sensorIndex = new System.Collections.Generic.Dictionary<string, SensorValue>(System.StringComparer.OrdinalIgnoreCase);
            iMax = sensorValues.Count;
            for (int i = 0; i < iMax; i++)
            {
                sensorValue = sensorValues[i];
                if (sensorValue == null)
                    continue;
                if (string.IsNullOrWhiteSpace(sensorValue.Name))
                    continue;
                if (!sensorIndex.ContainsKey(sensorValue.Name))
                    sensorIndex.Add(sensorValue.Name, sensorValue);
            }
            if (sensorIndex.Count == 0)
                return false;
            names = (from o in sensorIndex
                     select o.Value.Name).ToArray();

            query = (from o in storageManager.ObjectContext.WorkItemSensor
                     where (o.WorkItemId == workItemId) && (names.Contains(o.Name))
                     select o);
            var items = await Sidvall.WorkItemManager.Data.Entity.SystemContext.Current.DataManager.GetEntityObjectsAsync(query).ConfigureAwait(false);
            if (items == null)
                return false;
            if (items.Count == 0)
                return false;
            foreach (var item in items)
            {
                sensorValue = sensorIndex[item.Name];
                if ((logOldValue) && (item.ValueTimestamp != null) && ((sensorValue.ValueTimestamp == null) || (sensorValue.ValueTimestamp.Value > item.ValueTimestamp.Value)))
                {
                    workItemSensorLogs = new WorkItemSensorLogCollection();
                    workItemSensorLog = new WorkItemSensorLog()
                    {
                        Value = item.Value,
                        ValueTimestamp = item.ValueTimestamp.Value,
                        WorkItemSensorId = item.WorkItemSensorId,
                    };
                    workItemSensorLogs.Add(workItemSensorLog);
                    item.WorkItemSensorLog = workItemSensorLogs;
                }
                item.Value = sensorValue.Value;
                if (sensorValue.ValueTimestamp != null)
                    item.ValueTimestamp = sensorValue.ValueTimestamp.Value.ToUniversalTime();
                else
                    item.ValueTimestamp = null;
            }
            await Sidvall.WorkItemManager.Data.Entity.SystemContext.Current.DataManager.SaveChangesAsync(storageManager.ObjectContext).ConfigureAwait(false);

            return true;
        }

        #endregion
    }
}